From 2b1aa12f01f382652a3b6b9c7e51959dde194143 Mon Sep 17 00:00:00 2001 From: Ryan Lortie Date: Sat, 4 Jan 2014 02:25:43 -0500 Subject: [PATCH] GtkMenuTrackerItem: add an internal 'visible' flag Add an internal API for checking if a GtkMenuTrackerItem is visible, along with a signal for reporting changes in that flag. The item will become invisible in situations according to the new hidden-when='' attribute, which can be set to 'action-disabled' or 'action-missing'. This new flag doesn't actually do anything yet, and none of the consumers of GtkMenuTracker do anything with it (nor should they). A followup patch will address the issue. https://bugzilla.gnome.org/show_bug.cgi?id=688421 --- gtk/gtkmenutrackeritem.c | 90 ++++++++++++++++++++++++++++++++++++++++ gtk/gtkmenutrackeritem.h | 4 ++ 2 files changed, 94 insertions(+) diff --git a/gtk/gtkmenutrackeritem.c b/gtk/gtkmenutrackeritem.c index d81c9de8e5..fdda28f9fb 100644 --- a/gtk/gtkmenutrackeritem.c +++ b/gtk/gtkmenutrackeritem.c @@ -97,8 +97,14 @@ struct _GtkMenuTrackerItem guint toggled : 1; guint submenu_shown : 1; guint submenu_requested : 1; + guint hidden_when : 2; + guint is_visible : 1; }; +#define HIDDEN_NEVER 0 +#define HIDDEN_WHEN_MISSING 1 +#define HIDDEN_WHEN_DISABLED 2 + enum { PROP_0, PROP_IS_SEPARATOR, @@ -115,6 +121,7 @@ enum { }; static GParamSpec *gtk_menu_tracker_item_pspecs[N_PROPS]; +static guint gtk_menu_tracker_visibility_changed_signal; static void gtk_menu_tracker_item_init_observer_iface (GtkActionObserverInterface *iface); G_DEFINE_TYPE_WITH_CODE (GtkMenuTrackerItem, gtk_menu_tracker_item, G_TYPE_OBJECT, @@ -239,6 +246,46 @@ gtk_menu_tracker_item_class_init (GtkMenuTrackerItemClass *class) g_param_spec_boolean ("submenu-shown", "", "", FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE); g_object_class_install_properties (class, N_PROPS, gtk_menu_tracker_item_pspecs); + + gtk_menu_tracker_visibility_changed_signal = g_signal_new ("visibility-changed", GTK_TYPE_MENU_TRACKER_ITEM, + G_SIGNAL_RUN_FIRST, 0, NULL, NULL, + g_cclosure_marshal_VOID__BOOLEAN, G_TYPE_NONE, + 1, G_TYPE_BOOLEAN); +} + +/* This syncs up the visibility for the hidden-when='' case. We call it + * from the action observer functions on changes to the action group and + * on initialisation (via the action observer functions that are invoked + * at that time). + */ +static void +gtk_menu_tracker_item_update_visibility (GtkMenuTrackerItem *self) +{ + gboolean visible; + + switch (self->hidden_when) + { + case HIDDEN_NEVER: + visible = TRUE; + break; + + case HIDDEN_WHEN_MISSING: + visible = self->can_activate; + break; + + case HIDDEN_WHEN_DISABLED: + visible = self->sensitive; + break; + + default: + g_assert_not_reached (); + } + + if (visible != self->is_visible) + { + self->is_visible = visible; + g_signal_emit (self, gtk_menu_tracker_visibility_changed_signal, 0, visible); + } } static void @@ -294,6 +341,12 @@ gtk_menu_tracker_item_action_added (GtkActionObserver *observer, if (action_target) g_variant_unref (action_target); + + /* In case of hidden-when='', we want to Wait until after refreshing + * all of the properties to emit the signal that will cause the + * tracker to expose us (to prevent too much thrashing). + */ + gtk_menu_tracker_item_update_visibility (self); } static void @@ -313,6 +366,8 @@ gtk_menu_tracker_item_action_enabled_changed (GtkActionObserver *observer, self->sensitive = enabled; g_object_notify_by_pspec (G_OBJECT (self), gtk_menu_tracker_item_pspecs[PROP_SENSITIVE]); + + gtk_menu_tracker_item_update_visibility (self); } static void @@ -368,6 +423,11 @@ gtk_menu_tracker_item_action_removed (GtkActionObserver *observer, self->toggled = FALSE; self->role = GTK_MENU_TRACKER_ITEM_ROLE_NORMAL; + /* Backwards from adding: we want to remove ourselves from the menu + * -before- thrashing the properties. + */ + gtk_menu_tracker_item_update_visibility (self); + g_object_freeze_notify (G_OBJECT (self)); if (was_sensitive) @@ -413,6 +473,7 @@ _gtk_menu_tracker_item_new (GtkActionObservable *observable, { GtkMenuTrackerItem *self; const gchar *action_name; + const gchar *hidden_when; g_return_val_if_fail (GTK_IS_ACTION_OBSERVABLE (observable), NULL); g_return_val_if_fail (G_IS_MENU_MODEL (model), NULL); @@ -423,6 +484,23 @@ _gtk_menu_tracker_item_new (GtkActionObservable *observable, self->observable = g_object_ref (observable); self->is_separator = is_separator; + if (!is_separator && g_menu_item_get_attribute (self->item, "hidden-when", "&s", &hidden_when)) + { + if (g_str_equal (hidden_when, "action-disabled")) + self->hidden_when = HIDDEN_WHEN_DISABLED; + else if (g_str_equal (hidden_when, "action-missing")) + self->hidden_when = HIDDEN_WHEN_MISSING; + + /* Ignore other values -- this code may be running in context of a + * desktop shell or the like and should not spew criticals due to + * application bugs... + * + * Note: if we just set a hidden-when state, but don't get the + * action_name below then our visibility will be FALSE forever. + * That's to be expected since the action is missing... + */ + } + if (!is_separator && g_menu_item_get_attribute (self->item, "action", "&s", &action_name)) { GActionGroup *group = G_ACTION_GROUP (observable); @@ -803,3 +881,15 @@ gtk_menu_tracker_item_request_submenu_shown (GtkMenuTrackerItem *self, else gtk_menu_tracker_item_set_submenu_shown (self, shown); } + +gboolean +_gtk_menu_tracker_item_is_visible (GtkMenuTrackerItem *self) +{ + return self->is_visible; +} + +gboolean +_gtk_menu_tracker_item_may_disappear (GtkMenuTrackerItem *self) +{ + return self->hidden_when != HIDDEN_NEVER; +} diff --git a/gtk/gtkmenutrackeritem.h b/gtk/gtkmenutrackeritem.h index 9db30eb880..03709d6051 100644 --- a/gtk/gtkmenutrackeritem.h +++ b/gtk/gtkmenutrackeritem.h @@ -72,6 +72,10 @@ GMenuModel * _gtk_menu_tracker_item_get_submenu (GtkMenu gchar * _gtk_menu_tracker_item_get_submenu_namespace (GtkMenuTrackerItem *self); +gboolean _gtk_menu_tracker_item_may_disappear (GtkMenuTrackerItem *self); + +gboolean _gtk_menu_tracker_item_is_visible (GtkMenuTrackerItem *self); + gboolean gtk_menu_tracker_item_get_should_request_show (GtkMenuTrackerItem *self); void gtk_menu_tracker_item_activated (GtkMenuTrackerItem *self); -- 2.30.2